/*
 * KeyboardView.hpp
 *
 *  Created on: Jun 1, 2009
 *      Author: asantos
 */

#ifndef INPUTVIEW_HPP_
#define INPUTVIEW_HPP_


//Turns keyup keydown SDL events into semantically rich, domain specific events
//EG: z-key down -> move forward
class Simulation1InputView{
public:
	typedef void(PlayerMovementHandler)(long, long);
	typedef void(PlayerSelectHandler)(long, long);
private:
	SignalBroker& signalbroker;
	boost::signals::connection keyupconnection;
	boost::signals::connection keydownconnection;

	std::map<SDLKey, boost::function<void()> > keydownbindings;
	std::map<SDLKey, boost::function<void()> > keyupbindings;
	std::map<SDLKey, boost::function<void(long, long)> > keyheldbindings;
	std::map<SDLKey, bool> keys;
public:
	Simulation1InputView(SignalBroker& signalbroker):signalbroker(signalbroker){
		try{
			Signal<SDLEventsView::KeyDownHandler>& keydown = signalbroker.CreateOrGetExistingSignal<SDLEventsView::KeyDownHandler>("/sdlevent/keydown");
			keydownconnection = keydown.connect(boost::bind(&Simulation1InputView::KeyDown, this, _1));

			Signal<SDLEventsView::KeyUpHandler>& keyup = signalbroker.CreateOrGetExistingSignal<SDLEventsView::KeyUpHandler>("/sdlevent/keyup");
			keyupconnection = keyup.connect(boost::bind(&Simulation1InputView::KeyUp, this, _1));

			Signal<ClockView::TickHandler>& clocktick = signalbroker.CreateOrGetExistingSignal<ClockView::TickHandler>("/clock/tick");
			clocktick.connect(boost::bind(&Simulation1InputView::ApplyInput, this, _1, _2));

			signalbroker.CreateOrGetExistingSignal<PlayerMovementHandler>("/input/player1/moveup");
			signalbroker.CreateOrGetExistingSignal<PlayerMovementHandler>("/input/player1/movedown");
			signalbroker.CreateOrGetExistingSignal<PlayerSelectHandler>("/input/player1/select");
			signalbroker.CreateOrGetExistingSignal<PlayerMovementHandler>("/input/player2/moveup");
			signalbroker.CreateOrGetExistingSignal<PlayerMovementHandler>("/input/player2/movedown");
			signalbroker.CreateOrGetExistingSignal<PlayerSelectHandler>("/input/player2/select");

			//setup bindings
			//TODO: refactor out into an injected dependency (KeyBindings)
			keyheldbindings[SDLK_g] = boost::bind(&Simulation1InputView::Player1MoveUp, this, _1, _2);
			keyheldbindings[SDLK_b] = boost::bind(&Simulation1InputView::Player1MoveDown, this, _1, _2);
			keyheldbindings[SDLK_v] = boost::bind(&Simulation1InputView::Player1Select, this, _1, _2);

			keyheldbindings[SDLK_a] = boost::bind(&Simulation1InputView::Player2MoveUp, this, _1, _2);
			keyheldbindings[SDLK_z] = boost::bind(&Simulation1InputView::Player2MoveDown, this, _1, _2);
			keyheldbindings[SDLK_x] = boost::bind(&Simulation1InputView::Player2Select, this, _1, _2);

		}catch(SignalDoesNotExist& e){
			signalbroker.InvokeSignal<OutputStreamView::LogHandler>("/log/output", std::string(e.what()));
		}
	}
	void KeyUp(SDLKey key){
		if(keyupbindings.find(key)!=keyupbindings.end()){
			keyupbindings[key]();
		}
		keys[key] = false;

	}
	void KeyDown(SDLKey key){
		if(keydownbindings.find(key)!=keydownbindings.end()){
			keydownbindings[key]();
		}
		keys[key] = true;
	}

	void ApplyInput(long t, long dt){
		std::map<SDLKey, bool>::const_iterator itr = keys.begin();
		for(;itr != keys.end(); itr++){
			if(itr->second == true){
				if(keyheldbindings.find(itr->first) != keyheldbindings.end()){
					keyheldbindings.find(itr->first)->second(t, dt);
				}
			}
		}
	}

	void Player1MoveUp(long t, long dt){
		signalbroker.InvokeSignal<PlayerMovementHandler>("/input/player1/moveup", t, dt);
	}
	void Player1MoveDown(long t, long dt){
		signalbroker.InvokeSignal<PlayerMovementHandler>("/input/player1/movedown",t, dt);
	}
	void Player1Select(long t, long dt){
		signalbroker.InvokeSignal<PlayerSelectHandler>("/input/player1/select",t, dt);
	}
	void Player2MoveUp(long t, long dt){
		signalbroker.InvokeSignal<PlayerMovementHandler>("/input/player2/moveup", t, dt);
	}
	void Player2MoveDown(long t, long dt){
		signalbroker.InvokeSignal<PlayerMovementHandler>("/input/player2/movedown",t, dt);
	}
	void Player2Select(long t, long dt){
		signalbroker.InvokeSignal<PlayerSelectHandler>("/input/player2/select",t, dt);
	}
};


#endif /* KEYBOARDVIEW_HPP_ */
